perm filename HELP.SAI[PNT,HE]6 blob sn#572760 filedate 1981-03-14 generic text, type C, neo UTF8
COMMENT ⊗   VALID 00008 PAGES
C REC  PAGE   DESCRIPTION
C00001 00001
C00002 00002	ENTRY
C00003 00003	INTEGER #RECS,#LINKS,QUESTION_NODE,MENU_NODE,DISPLAY_NODE,PREVIOUS_DISPLAY_NODE
C00005 00004	PROCEDURE HELP_INIT
C00009 00005	PROCEDURE HELP_EXEC(INTEGER ARRAY INDEX,DATA STRING ARRAY KEYWORDS
C00017 00006	INTERNAL PROCEDURE HELP_END
C00018 00007	INTERNAL PROCEDURE HELP(STRING KEY(NULL))
C00019 00008	END
C00020 ENDMK
C⊗;
ENTRY;
BEGIN

DEFINE $$HELP=TRUE;
REQUIRE "HEADER.SAI[pnt,he]" SOURCE_FILE;

COMMENT
	This version makes use of the file HELP.RAN and accesses the
error messages randomly.  It gives better performance than the previous
version that retrieved messages sequentially from HELP.DAT.
	;
INTEGER #RECS,#LINKS,QUESTION_NODE,MENU_NODE,DISPLAY_NODE,PREVIOUS_DISPLAY_NODE;
INTEGER CURRENT_NODE;
INTEGER ARRAY NODE_STACK[1:10];
INTEGER STACKTOP;	COMMENT CURRENT_NODE=NODE_STACK[STACKTOP];
INTEGER CHAN,BRCHAR,COUNT,EOF,FLAG,NCHAR;
STRING FNUM,FKEY,FRAN;
	! break tables;
INTEGER CR_BREAK,PP_BREAK,BB_BREAK,IGNORECR_BREAK;


DEFINE $HEAD "<>"=<"******************** H E L P   M O D E   ********************************">;
DEFINE $TAIL "<>"=<"*************************************************************************">;

RCLASS IREC (INTEGER ARRAY I);
RCLASS SREC (STRING ARRAY S);
RPTR(IREC) $INDEX,$DATA,$RANACCS;
RPTR(SREC) $KEYWORDS;

STRING $HSTRING,$KSTRING,$BSTRING;	! help string,keyword stack;
INTEGER $LINE;				! top line being displayed;

BOOLEAN HELP_INITTED;
PROCEDURE HELP_INIT;
BEGIN "help_init" ! sets up the appropriate data arrays;

FNUM←"HELP.NUM[PNT,HE]";
FKEY←"HELP.KEY[PNT,HE]";
FRAN←"HELP.RAN[PNT,HE]";

OPEN(CHAN←GETCHAN,"DSK",'10,19,0,1000,BRCHAR,EOF);
LOOKUP(CHAN,FNUM,FLAG);
#RECS←WORDIN(CHAN);
#LINKS←WORDIN(CHAN);
QUESTION_NODE←WORDIN(CHAN);
MENU_NODE←WORDIN(CHAN);

	BEGIN "read in and execute"
		! data arrays ;
	STRING ARRAY KEYWORDS[1:#RECS];
	INTEGER ARRAY INDEX[1:#RECS];
	INTEGER ARRAY DATA[1:#LINKS];
	INTEGER ARRAY RANACCS[1:#RECS];


	INTEGER I;
		! load up the arrays;
	ARRYIN(CHAN,INDEX[1],#RECS);
	ARRYIN(CHAN,DATA[1],#LINKS);
	ARRYIN(CHAN,RANACCS[1],#RECS);
	RELEASE(CHAN);

	! now get the keywords;
	OPEN(CHAN←GETCHAN,"DSK",0,19,0,1000,BRCHAR,EOF);
	LOOKUP(CHAN,FKEY,FLAG);
	! initialize the break tables;
	SETBREAK(PP_BREAK←GETBREAK,"%",NULL,"INS");
	SETBREAK(CR_BREAK←GETBREAK,LF,CR,"INS");
	SETBREAK(BB_BREAK←GETBREAK,"\",NULL,"INS");
	SETBREAK(IGNORECR_BREAK←GETBREAK,NULL,LF,"INS");
	INPUT(CHAN,PP_BREAK);	! get to beginning of data;
	INPUT(CHAN,CR_BREAK);	! prime it first;
	FOR I←1 STEP 1 UNTIL #RECS DO KEYWORDS[I]←INPUT(CHAN,CR_BREAK);
				! get the keywords;

	RELEASE(CHAN);
				! prepare input file for HELP MESSAGES ;
	OPEN(CHAN←GETCHAN,"DSK",0,19,0,NCHAR,BRCHAR,EOF);
	LOOKUP(CHAN,FRAN,FLAG);

	! put the data into records so as not to lose them ;
	$INDEX←NEW_RECORD(IREC);
		MEMORY[LOCATION(IREC:I[$INDEX])]↔MEMORY[LOCATION(INDEX)];
	$RANACCS←NEW_RECORD(IREC);
		MEMORY[LOCATION(IREC:I[$RANACCS])]↔MEMORY[LOCATION(RANACCS)];
	$DATA←NEW_RECORD(IREC);
		MEMORY[LOCATION(IREC:I[$DATA])]↔MEMORY[LOCATION(DATA)];
	$KEYWORDS←NEW_RECORD(SREC);
		MEMORY[LOCATION(SREC:S[$KEYWORDS])]↔MEMORY[LOCATION(KEYWORDS)];
	END "read in and execute";
	
HELP_INITTED←TRUE;
DISPLAY_NODE←CURRENT_NODE←QUESTION_NODE;
STACKTOP←0;
END "help_init";
PROCEDURE HELP_EXEC(INTEGER ARRAY INDEX,DATA; STRING ARRAY KEYWORDS;
			INTEGER ARRAY RANACCS);
BEGIN "help_exec"
SIMPLE INTEGER PROCEDURE NLINES(STRING S);
BEGIN	STRING S1; INTEGER BR;
	! counts number of lines in the string ;
	S1←S;
	S1←SCAN(S1,IGNORECR_BREAK,BR);
	RETURN(LENGTH(S)-LENGTH(S1));
END;

STRING PROCEDURE LOPLINES(REFERENCE STRING S; INTEGER N);
BEGIN	! lops off the first N lines of string S and returns it;
	STRING S1; INTEGER I,BR;
	S1←NULL;
	FOR I←1 STEP 1 UNTIL N DO
		BEGIN S1←S1&SCAN(S,CR_BREAK,BR);
		IF BR=LF THEN S1←S1&CRLF ELSE DONE;
		END;
	RETURN(S1);
END;

PROCEDURE HDISPLAY;
BEGIN	! displays a windowful;
	STRING HSTRING,DSTRING; INTEGER I;
	HSTRING←$HSTRING;
	DSTRING←LOPLINES(HSTRING,$LINE-1);
	IF HSTRING THEN DSTRING←LOPLINES(HSTRING,LASTLINE[$TTYTYPE]-9);
	FOR I←NLINES(DSTRING) STEP 1 UNTIL LASTLINE[$TTYTYPE]-11
		DO DSTRING←DSTRING&" "&CRLF;
	IF HSTRING THEN DSTRING←DSTRING&"<more can be seen by hitting formfeed>";
	OUTDPW($HEAD&CRLF&DSTRING&CRLF&$KSTRING&$BSTRING&$TAIL,
		-3,LASTLINE[$TTYTYPE]-4);
END;
	! procedure returning the appropriate help message;
STRING PROCEDURE MESSAGES(INTEGER KEY);
BEGIN	INTEGER MESSAGE_LENGTH,MESSAGE_START,MESSAGE_RECORD; STRING S;
	MESSAGE_RECORD←(RANACCS[KEY] DIV 640)+1;
	MESSAGE_START←RANACCS[KEY] MOD 640;
	MESSAGE_LENGTH←RANACCS[KEY+1]-RANACCS[KEY];

	USETI(CHAN,MESSAGE_RECORD);
	NCHAR←MESSAGE_START;	S←INPUT(CHAN,0); ! gets us to beginning of mess ;
	NCHAR←MESSAGE_LENGTH;	S←INPUT(CHAN,0);	! gets us the message ;
	RETURN(S);
END;


SIMPLE INTEGER PROCEDURE ANCESTOR;
	IF STACKTOP=1 THEN RETURN(CURRENT_NODE) ELSE
		RETURN(NODE_STACK[STACKTOP-1]);

PROCEDURE DISPLAY(INTEGER NODE);
	    BEGIN "printing"
	    STRING HSTRING,KSTACK,BSTRING;INTEGER BR;INTEGER TPTR,LL,UL;
	    LL←INDEX[NODE]+1;UL←INDEX[NODE+1];
	    HSTRING←NULL;
	    FOR TPTR←LL STEP 1 UNTIL UL
		DO HSTRING←HSTRING&CVTAB(KEYWORDS[DATA[TPTR]]
			&TAB)&MESSAGES(DATA[TPTR])&CRLF;
	    KSTACK←"ANCESTORS:";
	    FOR TPTR←STACKTOP STEP -1 UNTIL 1 DO
		KSTACK←KSTACK&TAB&KEYWORDS[NODE_STACK[TPTR]];
	    $KSTRING←CVTAB(KSTACK&CRLF);
	    $HSTRING←HSTRING&CRLF;
	    IF CURRENT_NODE≠QUESTION_NODE THEN
	    BEGIN
	    BSTRING←"BRETHREN:";
	    TPTR←ANCESTOR;
	    LL←INDEX[TPTR]+1;UL←INDEX[TPTR+1];
	    FOR TPTR←LL STEP 1 UNTIL UL DO
		BSTRING←BSTRING&" "&KEYWORDS[DATA[TPTR]];
	    END ELSE BSTRING←NULL;
	    $BSTRING←CVTAB(BSTRING&CRLF);
	    $LINE←1;
	    HDISPLAY;
	    OUTSTR("#### ");
	    BEGIN INTEGER C;
		WHILE(C←CALL(0,"SNEAKW"))=FF OR C=VERTICAL_TAB DO
		BEGIN
		IF C=FF THEN
			$LINE←($LINE+LASTLINE[$TTYTYPE]-10) MIN
				((NLINES($HSTRING) - LASTLINE[$TTYTYPE]+13) MAX 1)
		ELSE	$LINE← ($LINE - LASTLINE[$TTYTYPE]+10) MAX 1;
		INCHRW; HDISPLAY; OUTSTR(CRLF&"#### ");
		END;
	    END;
	    PREVIOUS_DISPLAY_NODE←NODE;
	    END "printing";

INTEGER PROCEDURE CHECK_SUCCESSORS(STRING KEY; INTEGER NODE);
	BEGIN
	INTEGER I;
	FOR I←INDEX[NODE]+1 STEP 1 UNTIL INDEX[NODE+1] DO
		IF EQU(KEY,KEYWORDS[DATA[I]]) THEN RETURN(DATA[I]);
	RETURN(0);
	END;

INTEGER PROCEDURE CHECK_ANCESTORS(STRING KEY);
	BEGIN
	INTEGER I;
	FOR I←STACKTOP STEP -1 UNTIL 1 DO
		IF EQU(KEY,KEYWORDS[NODE_STACK[I]]) THEN RETURN(NODE_STACK[I]);
	RETURN(0);
	END;

PROCEDURE STACK(INTEGER NODE);
	BEGIN
	INTEGER I;
	FOR I←STACKTOP STEP -1 UNTIL 1 DO
		IF NODE=NODE_STACK[I] THEN BEGIN STACKTOP←I; RETURN END;
	NODE_STACK[STACKTOP←STACKTOP+1]←NODE;
	END;

PROCEDURE HELPER;
BEGIN	STRING KEY; INTEGER BROTHER_NODE,ANCESTOR_NODE,SUCCESSOR_NODE;
	DO BEGIN
	STACK(CURRENT_NODE);
	IF PREVIOUS_DISPLAY_NODE≠DISPLAY_NODE THEN DISPLAY (DISPLAY_NODE)
		ELSE OUTSTR("#### ");
	KEY←INCHWL;
	IF EQU(KEY,"?") THEN DISPLAY_NODE←CURRENT_NODE←QUESTION_NODE
	    ELSE IF EQU(KEY,"MENU") THEN DISPLAY_NODE←CURRENT_NODE←MENU_NODE
	    ELSE IF EQU(KEY,"UP") THEN
			DISPLAY_NODE←CURRENT_NODE←ANCESTOR
	    ELSE IF EQU(KEY,NULL) OR EQU(KEY,"DONE") THEN
			DISPLAY_NODE←CURRENT_NODE
	    ELSE IF EQU(KEY,KEYWORDS[CURRENT_NODE]) THEN
			DISPLAY_NODE←CURRENT_NODE
	    ELSE IF (SUCCESSOR_NODE←CHECK_SUCCESSORS(KEY,CURRENT_NODE)) THEN
			DISPLAY_NODE←CURRENT_NODE←SUCCESSOR_NODE
	    ELSE IF (BROTHER_NODE←CHECK_SUCCESSORS(KEY,ANCESTOR))
			THEN BEGIN DISPLAY_NODE←CURRENT_NODE←BROTHER_NODE;
				STACKTOP←STACKTOP-1 END
	    ELSE IF (ANCESTOR_NODE←CHECK_ANCESTORS(KEY))
			THEN DISPLAY_NODE←CURRENT_NODE←ANCESTOR_NODE
	    ELSE DISPLAY_NODE←QUESTION_NODE;
	END UNTIL EQU(KEY,"DONE");
END;

PREVIOUS_DISPLAY_NODE←0;	! assume nothing displayed ;
HELPER;
END "help_exec";
INTERNAL PROCEDURE HELP_END;
IF HELP_INITTED THEN
BEGIN			! release the break tables;
INTEGER I;
FOR I←IGNORECR_BREAK,PP_BREAK,CR_BREAK,BB_BREAK DO RELBREAK(I);
RELEASE(CHAN);		! release the data file channel;
$INDEX←NULL_RECORD; $DATA←NULL_RECORD; $KEYWORDS←NULL_RECORD;$RANACCS←NULL_RECORD;
HELP_INITTED←FALSE;
END;
INTERNAL PROCEDURE HELP(STRING KEY(NULL));
BEGIN
	IF NOT HELP_INITTED THEN HELP_INIT;
	IF NOT EQU(KEY,NULL) THEN
	BEGIN INTEGER I;
		FOR I←#RECS STEP -1 UNTIL 1 DO IF EQU(KEY,SREC:S[$KEYWORDS][I])
			THEN DONE;
		IF I=0 THEN BEGIN PRINT("KEYWORD "&KEY&" IS UNKNOWN"&CRLF);
			    DISPLAY_NODE←CURRENT_NODE←QUESTION_NODE;
			    END
		ELSE BEGIN DISPLAY_NODE←CURRENT_NODE←I; STACKTOP←0; END;
	END;
	HELP_EXEC(IREC:I[$INDEX],IREC:I[$DATA],SREC:S[$KEYWORDS],
		IREC:I[$RANACCS]);
END;
END;